package com.kly.user.task;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.net.NetUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.fqgj.common.api.Response;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.common.utils.StringUtils;
import com.fqgj.log.factory.LogFactory;
import com.fqgj.log.interfaces.Log;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.eventbus.AsyncEventBus;
import com.kly.enums.ParameterTypeEnum;
import com.kly.service.MemberService;
import com.kly.user.config.NacosValueConfig;
import com.kly.user.db.dao.*;
import com.kly.user.db.entity.*;
import com.kly.user.dto.TrafficSourceDto;
import com.kly.user.dto.vo.TrafficSourceReq;
import com.kly.user.enums.*;
import com.kly.user.eventbus.ActionEnum;
import com.kly.user.eventbus.Event;
import com.kly.user.service.UserTrafficSourceService;
import com.kly.user.serviceImpl.traffic.wlm.WLMTrafficHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * who like me 下发
 */
@Component
public class WLMIssueTask {
    private static Log logger = LogFactory.getLog(WLMIssueTask.class);

    @Autowired
    private UserDao userDao;

    @Resource
    private MemberService memberService;

    @Resource
    UserWlmDao userWlmDao;

    @Resource
    UserWlmLogDao userWlmLogDao;

    @Resource
    AsyncEventBus pushEventBus;
    @Resource
    private UserTrafficSourceService userTrafficSourceService;

    @Autowired
    IssueConfigDao issueConfigDao;

    @Autowired
    IssueUserDao issueUserDao;

    @Resource
    IssueWlmRecordDao issueWlmRecordDao;

    @Resource
    CustomersUserDao customersUserDao;

    @NacosValue(value = "${wlm.job.executor.ip}", autoRefreshed = true)
    private String taskJobExecutor;

    @NacosValue(value = "${task.job.wlm.version:1}", autoRefreshed = true)
    private Integer taskJobWLMVersion;

    @NacosValue(value = "${meboo.homepage.new.policy.show.detail:false}", autoRefreshed = true)
    private boolean showHomepageNewPolicyVersionDetail;

    // 流量池测试开关
    @NacosValue(value = "${issue.user.pool.test:false}", autoRefreshed = true)
    private boolean issueUserPoolTest;
    // 流量池测试用户
    @NacosValue(value = "${issue.user.pool.test.userCode}", autoRefreshed = true)
    private String issueUserPoolTestUserCode;
    @Resource
    NacosValueConfig nacosValueConfig;


    private String localIP = NetUtil.getLocalhostStr();

    @Scheduled(fixedDelay = 30000)
    public void execute() {
        logger.info("==WLMIssueTask 开始执行wlm任务 ==");
        if (!taskJobExecutor.contains(localIP)) {
            logger.info("=============WLMIssueTask 当前机器IP不允许执行任务, currentLocalAddress:{}, onlyExecuteTaskIn:{}", localIP, taskJobExecutor);
            return;
        }

        //查询是否存在规则
        //最近三天查询注册时间大于30s的用户
        IssueConfigEntity issueConfigEntity = issueConfigDao.queryIssueConfig(1);
        if (issueConfigEntity == null) {
            logger.info("==WLMIssueTask 开始执行wlm任务 没有找到对应的数据库配置==");
            return;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, -2);
        Date date = calendar.getTime();
        int count = userDao.getRegisterDateUserCount(String.valueOf(date.getTime()));
        logger.info("==WLMIssueTask 最近2天活跃的用户数==,count:{}", count);
        if (count < 0) {
            logger.info("==WLMIssueTask 最近2天活跃的用户数 小于0 任务终止==,count:{}", count);
            return;
        }


        int pageSize = (count / 100) + 1;
        for (int i = 0; i < pageSize; i++) {
            List<UserEntity> userEntityList = userDao.getRegisterDateUserLimit(String.valueOf(date.getTime()), i);
            logger.info("==WLMIssueTask 最近三天活跃的用户数==,page:{}", i + 1);
            for (UserEntity userEntity : userEntityList) {
                try {
                    if (userEntity.getRegisterDate() == null) {
                        logger.info("==WLMIssueTask 当前用户没有注册时间==,userCode:{},name:{}", userEntity.getUserCode(), userEntity.getNickName());
                        continue;
                    }
                    Date now = new Date();
                    if (DateUtil.between(now, userEntity.getRegisterDate(), DateUnit.SECOND) < issueConfigEntity.getRegisterTime()) {
                        logger.info("==WLMIssueTask 不满足配置条件的注册时间==,userCode:{},name:{}", userEntity.getUserCode(), userEntity.getNickName());
                        continue;
                    }

                    WLMTrafficHandler.wlmBaseMap.get(userEntity.getAppCode()).dealCondition(issueConfigEntity, userEntity);

                } catch (Exception e) {
                    logger.info("==WLMIssueTask error ==,userCode:{}", userEntity.getUserCode(), e);
                }
            }
            if (userEntityList.size() != 100) {
                break;
            }
        }

//        int i = 0;
//        while (true) {
//            logger.info("==WLMIssueTask 最近2天活跃的用户数==,page:{}", i + 1);
//            List<UserEntity> userEntityList = userDao.getRegisterDateUserLimit(String.valueOf(date.getTime()), i);
//            if (CollectionUtils.isEmpty(userEntityList)) {
//                logger.info("==WLMIssueTask 最近2天活跃的用户数,最后一页，数据为空了==,page:{}", i + 1);
//                break;
//            }
//
//            for (UserEntity userEntity : userEntityList) {
//                try {
//                    if (userEntity.getRegisterDate() == null) {
//                        logger.error("==WLMIssueTask 当前用户没有注册时间==,userCode:{},name:{}", userEntity.getUserCode(), userEntity.getNickName());
//                        continue;
//                    }
//                    Date now = new Date();
//                    if (DateUtil.between(now, userEntity.getRegisterDate(), DateUnit.SECOND) < issueConfigEntity.getRegisterTime()) {
//                        logger.info("==WLMIssueTask 不满足配置条件的注册时间==,userCode:{},name:{},注册时间要求:{},用户注册时间:{}", userEntity.getUserCode(), userEntity.getNickName(), issueConfigEntity.getRegisterTime(), DateUtil.between(now, userEntity.getRegisterDate(), DateUnit.SECOND));
//                        continue;
//                    }
//
//                   WLMTrafficHandler.wlmBaseMap.get(userEntity.getAppCode()).dealCondition(issueConfigEntity, userEntity);
//                } catch (Exception e) {
//                    logger.info("==WLMIssueTask error ==,userCode:{}", userEntity.getUserCode(), e);
//                }
//            }
//
//            i++;
//        }

    }

    /**
     * 条件判断处理
     *
     * @param issueConfigEntity
     * @param userEntity
     */
    private void dealCondition(IssueConfigEntity issueConfigEntity, UserEntity userEntity) {
        Integer wlmAmount = wlmAmount(userEntity.getUserCode());
        logger.info("==WLMIssueTask==,userCode:{},name:{},当日已经下发:{}", userEntity.getUserCode(), userEntity.getNickName(), wlmAmount);
        if (wlmAmount >= issueConfigEntity.getIssueCount()) {
            logger.info("==WLMIssueTask 当前用户的当日wlm下发次数已经足够==,userCode:{},name:{}", userEntity.getUserCode(), userEntity.getNickName());
            return;
        }

        boolean online = userEntity.getOnline() == 1;
        //在线
        if (online) {
            int issueTime = getWLMIssueTime(issueConfigEntity, wlmAmount);
            logger.info("==WLMIssueTask 在线==,userCode:{},name:{},下次应该下发的时间mins是:{}", userEntity.getUserCode(), userEntity.getNickName(), issueTime);
            push(issueConfigEntity, wlmAmount, userEntity, issueTime);
            return;
        }

        logger.info("==WLMIssueTask 不在线==,userCode:{},name:{}", userEntity.getUserCode(), userEntity.getNickName());
        if (isToday(userEntity.getGmtModified())) {
            logger.info("==WLMIssueTask 不在线 但今天有启动过==,userCode:{},name:{}", userEntity.getUserCode(), userEntity.getNickName());
            //当天wlm数量
            //距离上次下发时间
            int IssueTime = wlmAmount * issueConfigEntity.getIssueHour();
            push(issueConfigEntity, wlmAmount, userEntity, IssueTime);
        } else {
            logger.info("==WLMIssueTask 不在线 但今天没有启动过==,userCode:{},name:{}", userEntity.getUserCode(), userEntity.getNickName());
            SimpleDateFormat format0 = new SimpleDateFormat("HHmmss");
            Time time = new Time(new Date().getTime());
            if (Integer.parseInt(format0.format(issueConfigEntity.getIssueTime())) < Integer.parseInt(format0.format(time))) {
                int IssueTime = wlmAmount * issueConfigEntity.getIssueHour();
                push(issueConfigEntity, wlmAmount, userEntity, IssueTime);
            }
        }

    }

    /**
     * 判断时间是否为今天
     *
     * @param date
     * @return
     */
    public static boolean isToday(Date date) {
        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
        //格式化为相同格式
        return fmt.format(date).equals(fmt.format(new Date()));
    }


    /**
     * 读取当天wlm数
     *
     * @param userCode
     * @return
     */
    private Integer wlmAmount(String userCode) {
//        List<UserWlmEntity> todayWlmRecords = userWlmDao.getTodayWlmRecords(userCode);
//        return todayWlmRecords.size();
        return issueWlmRecordDao.getWlmNum(userCode);

    }

    /**
     * 下发
     *
     * @param issueConfigEntity
     * @param wlmAmount
     * @param userEntity
     * @param issueTime
     */
    private void push(IssueConfigEntity issueConfigEntity, Integer wlmAmount, UserEntity userEntity, int issueTime) {
        if (wlmAmount == 0) {
            logger.info("==WLMIssueTask 今日无下发==,userCode:{},name:{},今日无下发", userEntity.getUserCode(), userEntity.getNickName());
            String userCode = getIssueUserCode(userEntity);
            if (userCode == null) {
                logger.info("==WLMIssueTask 今日无下发==,userCode:{},name:{},找不到目标model", userEntity.getUserCode(), userEntity.getNickName());
                return;
            }
            logger.info("==WLMIssueTask 今日无下发 找到 目标model==,userCode:{},name:{},model:{}", userEntity.getUserCode(), userEntity.getNickName(), userCode);
            addUserWlm(userEntity.getUserCode(), userCode, userEntity.getAppCode());
            return;
        }

        logger.info("==WLMIssueTask 今日有下发==,userCode:{},name:{},今日无下发", userEntity.getUserCode(), userEntity.getNickName());
        if (wlmAmount < issueConfigEntity.getIssueCount()) {
            long distanceWLMTime = distanceWLMTime(userEntity.getUserCode());
            if (distanceWLMTime > issueTime) {
                //下发
                String userCode = getIssueUserCode(userEntity);
                if (userCode != null) {
                    addUserWlm(userEntity.getUserCode(), userCode, userEntity.getAppCode());
                }
            }
        }
    }

    private String getIssueUserCode(UserEntity userEntity) {
        if (!AppCodeEnum.PP.getAppCode().equals(userEntity.getAppCode())) {
            return getUser(userEntity.getUserCode(), userEntity.getLookingFor());
        }
        if (isOrganic(userEntity)) {
            if (StringUtils.isEmpty(nacosValueConfig.ppWlmIssueFixUserCode())) {
                return null;
            }
            // 随机取一个配置
            final List<String> userCodes = Splitter.on(",").splitToList(nacosValueConfig.ppWlmIssueFixUserCode());

            final List<UserEntity> userEntities = userDao.listUsers(userCodes);
            if (CollectionUtils.isEmpty(userEntities)) {
                logger.error("===未维护userCode, userCode:{}", nacosValueConfig.ppWlmIssueFixUserCode());
                return null;
            }
            return userEntities.get(0).getUserCode();
        }
        return getUser(userEntity.getUserCode(), userEntity.getLookingFor());
    }

    public static void main(String[] args) {
        List<String> allUsers = Lists.newArrayList("12312", "13123");
        List<String> onlineUsers = Lists.newArrayList("棒棒");
        allUsers.retainAll(onlineUsers);
        System.out.println(allUsers);

    }

    /**
     * 读取下发用户
     *
     * @param userCode
     * @param lookingFor
     * @return
     */
    private String getUser(String userCode, int lookingFor) {
        List<String> userCodeList = new ArrayList<>();

        logger.info("WLMIssueTask 获取哪个model可以下发 开始 taskJobWLMVersion" + taskJobWLMVersion);
        if (taskJobWLMVersion == 5) {
            logger.info("WLMIssueTask userCode" + userCode);
            Response<Boolean> response = memberService.ifMember(userCode);
            if (response.isSuccess()) {
                Boolean ifmMember = response.getData();
                logger.info("WLMIssueTask ifmMember" + ifmMember);
                List<Integer> poolNums = new ArrayList<>();
                if (ifmMember) {
                    poolNums.add(1);
                } else {
                    poolNums.add(2);
                    poolNums.add(3);
                    poolNums.add(4);
                }
                logger.info("===WLMIssueTask, 流量池:" + poolNums);
                List<IssueUserPoolEntity> userCodeEntityList = new ArrayList<>();
                //【pp-v1.1.0】流量侧-自然流量>>wlm>>2. 仅下发本次提供的user code（类似素人建联）优先下发在线的user code，其次下发不在线的user code，不区分性别
                CustomersUserEntity customersUserEntity = customersUserDao.getCustomer(userCode);
                if (customersUserEntity == null) {
                    logger.error("===WLMIssueTask, 当前用户 没有 对应的customer_code:" + poolNums);
                    userCodeEntityList = userDao.queryIssueUserPoolV2(userCode, lookingFor, poolNums, 1, UserType.ALL.getType());
                } else {
                    logger.error("===WLMIssueTask, 当前用户 找到 对应的customer_code:" + poolNums);
                    userCodeEntityList = userDao.queryIssueUserPoolV3(userCode,customersUserEntity.getCustomerCode(), lookingFor, poolNums, 1, UserType.ALL.getType());
                }
                if (CollectionUtils.isNotEmpty(userCodeEntityList)) {
                    logger.info("===WLMIssueTask, userCode:{}, 返回数据: {}", userCode, JSONObject.toJSONString(userCodeEntityList));
                    userCodeList = userCodeEntityList.stream().map(IssueUserPoolEntity::getUserCode).collect(Collectors.toList());
                } else {
                    logger.error("===WLMIssueTask,找不到能下发wlm的mmodel:" + poolNums);
                }
            }
        }

        String result = null;
        if (!userCodeList.isEmpty()) {
            result = userCodeList.get(0);
            issueUserDao.updateConnectCount(userCodeList);
        }

        logger.info("WLMIssueTask 获取哪个model可以下发 结束 taskJobWLMVersion" + taskJobWLMVersion);
        return result;
    }


    /**
     * 是否走非自然流量策略
     * <p>
     * 【pp-v1.1.0】流量侧-自然流量>>wlm>>2. 仅下发本次提供的user code（类似素人建联）优先下发在线的user code，其次下发不在线的user code，不区分性别
     */
    private boolean isOrganic(UserEntity currentUser) {
        TrafficSourceReq req = TrafficSourceReq.builder()
                .userCode(currentUser.getUserCode())
                .appCode(currentUser.getAppCode())
                .mobile(currentUser.getMobile())
                .email(currentUser.getEmail())
                .build();
        Response<TrafficSourceDto> resp = userTrafficSourceService.getTrafficSource(req);
        if (!resp.isSuccess() || resp.getData() == null) {
            return false;
        }

        // 如果开关关闭，一律走非自然流量策略；如果开关开启，自然流量走自然流量策略
        return TrafficSourceEnum.Organic.equals(resp.getData().getTrafficSourceEnum());
    }

    private void pushMessage(String fromUseCode, String toUserCode, AppEnum appEnum) {

        pushEventBus.post(buildEvent(fromUseCode, toUserCode, appEnum));

    }

    private Event buildEvent(String fromUseCode, String toUserCode, AppEnum appEnum) {
        Map<String, Integer> params = Maps.newHashMap();
        params.put("type", ParameterTypeEnum.WHO_LIKE_ME.getId());
        return Event.builder().eventActionEnum(ActionEnum.PUSH_MSG).fromUserCode(fromUseCode).toUserCode(toUserCode).app(appEnum).content(JSONObject.toJSONString(params)).build();
    }


    /**
     * 距离上次WLM下发时间＞（2+今日下发WLM次数*2）mim
     *
     * @param issueConfigEntity
     * @param wlmAmount
     * @return
     */
    private int getWLMIssueTime(IssueConfigEntity issueConfigEntity, Integer wlmAmount) {
        return issueConfigEntity.getIssueOne() + (wlmAmount * issueConfigEntity.getIssueTwo());
    }

    /**
     * 读取
     *
     * @param userCode
     * @return
     */
    private long distanceWLMTime(String userCode) {
        UserWlmEntity todayWlmRecord = userWlmDao.getLastWlmRecord(userCode);
        return DateUtil.between(DateUtil.date(), todayWlmRecord.getSendWlmTime(), DateUnit.MINUTE);
    }


    /**
     * 添加记录
     *
     * @param userCode
     * @param userCodeFriend
     */
    public void addUserWlm(String userCode, String userCodeFriend, String app) {
        UserWlmEntity userWlmEntity = new UserWlmEntity();
        userWlmEntity.setUserCode(userCodeFriend);
        userWlmEntity.setUserCodeWlm(userCode);
        userWlmEntity.setWlmType(LikeEnum.LIKE.getType());
        userWlmEntity.setSendWlmTime(new Date());
//        userWlmEntity.setConnectType(WLMType.WLM.getCode());
        userWlmDao.insert(userWlmEntity);

        userWlmLogDao.addWlmLog(userWlmEntity);

        addWLMRecord(userCode, userCodeFriend);
        // 推送消息
        pushMessage(userCodeFriend, userCode, AppEnum.getEnumByUserAppFlat(app));
    }


    /**
     * 添加记录
     *
     * @param userCode
     * @param userCodeFriend
     */
    private void addWLMRecord(String userCode, String userCodeFriend) {
        IssueWlmRecordEntity issueWlmRecordEntity = new IssueWlmRecordEntity();
        issueWlmRecordEntity.setUserCode(userCode);
        issueWlmRecordEntity.setModelUserCode(userCodeFriend);
        UserEntity userEntity = userDao.selectByUserCode(userCodeFriend);
        issueWlmRecordEntity.setOnlineStatus(userEntity.getOnline());
        issueWlmRecordDao.insert(issueWlmRecordEntity);
    }

    //读取配置表  //参数 用户注册时间s 下发时间第一个变量 下发时间第二个变量  配置下发时间(time) 当日下发最大次数

    //配置表 用户like back变量(0.00) like back数量  距离上次下发时间公式 min第一个参数 第二个参数  h参数  时间(time)

    // 根据配置读取注册时间内的用户 已激活的用户
    // 判断用户是否在线
    // 添加是否为会员标识
    // 如果不在线 判断用户今日是否启动过app
    // 查询今日下发次数
    // 距离上次下发时间
    //(距离上次下发WLM时间＞（2+今日下发WLM次数*2）mim)

}
